package com.custom.jdbc.executor.convert;

import com.custom.comm.utils.CustomUtil;
import com.custom.jdbc.configuration.DbGlobalConfig;
import com.custom.jdbc.executebody.SqlExecutorBody;
import com.custom.jdbc.handler.*;

import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author XiaoBai
 * @since 2024/3/30 0030 21:06
 */
@SuppressWarnings("unchecked")
public abstract class AbstractRsHandler implements TypeMappedHandler {

    /**
     * 类型转换寄存
     */
    protected final static Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLER_CACHE = new ConcurrentHashMap<>();
    private final DbGlobalConfig globalConfig;

    public AbstractRsHandler(DbGlobalConfig globalConfig) {
        this.globalConfig = globalConfig;
    }

    public boolean isUnderlineToCamel() {
        return globalConfig.getStrategy().isUnderlineToCamel();
    }


    static {
        registerType(Integer.class, new IntegerTypeHandler());
        registerType(Long.class, new LongTypeHandler());
        registerType(Double.class, new DoubleTypeHandler());
        registerType(Float.class, new FloatTypeHandler());
        registerType(Character.class, new CharacterTypeHandler());
        registerType(Short.class, new ShortTypeHandler());
        registerType(Boolean.class, new BooleanTypeHandler());
        registerType(String.class, new StringTypeHandler());
        registerType(BigDecimal.class, new BigDecimalTypeHandler());
        registerType(Date.class, new DateTypeHandler());
        registerType(Timestamp.class, new TimestampTypeHandler());
        registerType(Object.class, new UnknownTypeHandler());
    }

    public static void registerType(Class<?> cls, TypeHandler<?> typeHandler) {
        ALL_TYPE_HANDLER_CACHE.putIfAbsent(cls, typeHandler);
    }


    @SuppressWarnings("unchecked")
    public static <T> TypeHandler<T> getTargetTypeHandler(Class<T> mappedType) {
        if (mappedType == null) {
            return (TypeHandler<T>) ALL_TYPE_HANDLER_CACHE.get(Object.class);
        }
        TypeHandler<?> typeHandler = ALL_TYPE_HANDLER_CACHE.get(mappedType);
        if (typeHandler == null) {
            typeHandler =  ALL_TYPE_HANDLER_CACHE.get(Object.class);
        }
        return (TypeHandler<T>) typeHandler;
    }

    protected Map<String, Object> resToMap(ResultSet rs) throws SQLException {
        ResultSetMetaData rsMetaData = rs.getMetaData();
        Map<String, Object> resMap = new LinkedHashMap<>();
        // 循环取值
        for (int i = 0; i < rsMetaData.getColumnCount(); i++) {
            // 查询的列名
            String label = rsMetaData.getColumnLabel(i + 1);
            // 列名对应的值
            Object value = rs.getObject(label);

            resMap.put(label, value);
        }
        return resMap;
    }


    @Override
    public <T> T getTargetObject(Class<T> mappedType, ResultSet rs, int colIndex) throws Exception {
        TypeHandler<T> typeHandler = getTargetTypeHandler(mappedType);
        if (typeHandler == null) {
            return (T) rs.getObject(colIndex);
        }
        return typeHandler.getTypeValue(rs, colIndex);
    }


    @Override
    public void setQueryParam(SqlExecutorBody executorBody, PreparedStatement statement) throws Exception {
        Object[] parameters = executorBody.getSqlParams();
        if (parameters == null || parameters.length == 0) {
            return;
        }
        for (int i = 0; i < parameters.length; i++) {
            Object param = parameters[i];
            statement.setObject((i + 1), param);
        }
    }


    public <T> List<T> getTargetList(SqlExecutorBody executorBody, Class<T> mappedType, ResultSet rs, int colIndex) throws Exception {
        // 只取每一行的第一列
        List<T> list = new ArrayList<>();
        TypeHandler<T> typeHandler = getTargetTypeHandler(mappedType);
        while (rs.next()) {
            T val;
            if (typeHandler == null) {
                val = (T) rs.getObject(colIndex);
            } else {
                val = typeHandler.getTypeValue(rs, colIndex);
            }
            list.add(val);
        }
        return list;
    }


    public <T> T[] getTargetArrays(SqlExecutorBody executorBody, Class<T> mappedType, ResultSet rs, int colIndex, int count) throws Exception {
        int len = 0;
        T[] resArr = (T[]) Array.newInstance(mappedType, count);
        while (rs.next()) {
            T value;
            // 若数组的类型是基本类型，只取每一行的第一列
            if (CustomUtil.isBasicClass(mappedType)) {
                value = this.getTargetObject(mappedType, rs, colIndex);
            }
            // 否则视为自定义对象
            else {
                value = this.getTargetObject(executorBody, mappedType, rs);
            }
            Array.set(resArr, len, value);
            len ++;
        }
        return resArr;
    }


    public <T> Map<String, T> getTargetMap(SqlExecutorBody executorBody, Class<T> mappedType, ResultSet rs) throws Exception {
        ResultSetMetaData rsMetaData = rs.getMetaData();
        Map<String, T> map = new HashMap<>();
        // 该类型的转换处理
        AbstractTypeHandler<T> thisTypeHandler = (AbstractTypeHandler<T>) getTargetTypeHandler(mappedType);

        // 循环取值
        for (int i = 0; i < rsMetaData.getColumnCount(); i++) {
            // 查询的列名
            String label = rsMetaData.getColumnLabel(i + 1);
            // 列名对应的值
            T value = thisTypeHandler.getTypeValue(rs.getObject(label));
            if (isUnderlineToCamel()) {
                label = CustomUtil.underlineToCamel(label);
            }
            map.put(label, value);
        }
        return map;
    }

}
